#include "AssetManager.h"
#include "../AnimConfig.h"

#include <fstream>
using std::fstream;
using std::ios_base;

#if _DEBUG
#include "../Game.h"
#include "../Debug Console/DebugConsole.h"
#endif

#define SHADER_NAME_SIZE 256

struct tVertex
{
	D3DXVECTOR3 vPosition;
	D3DXVECTOR3 vNormal;
	// D3DCOLOR vColor;
	D3DXVECTOR2 vTexCoords;
};

CAssetManager::CAssetManager( void )
{

}

CAssetManager::~CAssetManager( void )
{
	m_vMeshes.clear( );
	m_vShaders.clear( );
}

void CAssetManager::Initialize( IDirect3DDevice9* pDev )
{
	m_pDev = pDev;
}

void CAssetManager::LoadShaders( const char* szFileName )
{
	fstream in;
	in.open( szFileName, ios_base::in );

	if( in.is_open( ) )
	{
		char nNumFiles;
		char szBuffer[SHADER_NAME_SIZE];
		ID3DXBuffer* pErrors = NULL;
		ID3DXEffect* pEffect = NULL;

		in.read( ( char* )&nNumFiles, sizeof( char ) );
		in.ignore( INT_MAX, '\n' );

		nNumFiles -= 48;

		for( unsigned int i = 0; i < ( unsigned int )nNumFiles; ++i )
		{
			in.getline( szBuffer, SHADER_NAME_SIZE, '\n' );
			in.ignore( INT_MAX, '\n' );

			// Create shader
			D3DXCreateEffectFromFile( m_pDev, szBuffer, 0, 0, D3DXSHADER_DEBUG, 0, &pEffect, &pErrors );

			// Are there erros?!
			#if _DEBUG

			if( pErrors != NULL )
				CGame::GetInstance( )->GetConsole( )->Display( ( char* )pErrors->GetBufferPointer( ) );

			#endif

			// Add this shader to the vector
			m_vShaders.push_back( pEffect );
		}

	}
	in.close( );
	in.clear( );
}

unsigned int CAssetManager::LoadTROGDOR( const char* szFileName )
{
	//std::ifstream in;
	//in.open( szFileName, std::ios_base::in | std::ios_base::binary);

	//unsigned int unIndex = -1;

	//if( in.good( ) )
	//{
	//	TMesh pMesh;

	//	// Create vertex declaration here
	//	D3DVERTEXELEMENT9 texturedDecl[] = 
	//	{
	//		{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 },
	//		{ 0,12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 },
	//		{ 0, 24, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0 },
	//		D3DDECL_END( )
	//	};
	//	m_pDev->CreateVertexDeclaration( texturedDecl, &trogdorDecl );


	//	D3DXCreateTextureFromFile( m_pDev, "Root/Resource/Textures/trogbmp.bmp", &pMesh.pTexture );

	//	int NumVerts = 0;
	//	int NumTris = 0;
	//	in.read((char*)&NumVerts, sizeof(int));

	//	void* tempVerts;
	//	m_pDev->CreateVertexBuffer(NumVerts*(sizeof(TROGTEX)),0, 0, D3DPOOL_DEFAULT, &pMesh.pVertBuffer, 0);
	//	pMesh.pVertBuffer->Lock( 0, 0, &tempVerts, 0 );
	//	in.read((char*)tempVerts, NumVerts*sizeof(TROGTEX));
	//	pMesh.pVertBuffer->Unlock( );


	//	in.read((char*)&NumTris, sizeof(int));

	//	void* tempIndex;
	//	m_pDev->CreateIndexBuffer(NumTris*sizeof(DWORD),0, D3DFMT_INDEX32, D3DPOOL_DEFAULT, &pMesh.pIndexBuffer, 0);
	//	pMesh.pIndexBuffer->Lock( 0, 0, &tempIndex, 0 );
	//	in.read((char*)tempIndex, sizeof(DWORD)*NumTris*3);
	//	pMesh.pIndexBuffer->Unlock( );

	//	pMesh.nNumTris = NumTris;
	//	pMesh.nNumVerts = NumVerts;

	//	unIndex = m_vMeshes.size( );
	//	m_vMeshes.push_back( pMesh );
	//}
	//in.close( );
	//in.clear( );

	return 0;
}

TMesh* CAssetManager::GetMesh( unsigned int nID )
{
	//TAnimMesh* test = (TAnimMesh*)m_vMeshes[nID];
	return m_vMeshes[nID];
}

ID3DXEffect* CAssetManager::GetShader( unsigned int nID )
{
	return m_vShaders[nID];
}

void CAssetManager::ShutdownMesh( TMesh* pMesh )
{
	// TODO!
	/// delete shit here, I leave it to you Ben!
}

void CAssetManager::Shutdown( void )
{
	for( unsigned int i = 0; i < m_vMeshes.size( ); ++i )
		ShutdownMesh( m_vMeshes[i] );
	
	m_vMeshes.empty( );
}

unsigned int CAssetManager::LoadAnimatedMesh( const char* szFileName )
{
	TAnimMesh* newMesh = new TAnimMesh;

	std::ifstream in(szFileName, std::ios_base::binary);

	if(in.good() && in.is_open())
	{
		unsigned int size;

		//read in the name
		char buffer[128];
		in.read((char*)&size, sizeof(size));
		in.read(buffer, size);
		buffer[size] = 0;

		in.read((char*)&size, sizeof(size));
		in.read(buffer, size);
		buffer[size] = 0;

		int numTextures;

		in.read((char*)&numTextures, sizeof(int));

		for(int i = 0; i < numTextures; ++i)
		{
			in.read((char*)&size, sizeof(size));
			in.read(buffer, size);
			buffer[size] = 0;
		}

		int numVerts;
		in.read((char*)&numVerts, sizeof(int));

		newMesh->nNumVerts = numVerts;

		std::vector<TANIMVERTEX> animVertex;
		animVertex.resize(numVerts);

		std::vector<std::vector<TInfluence>> influences;
		influences.resize(numVerts);

		for(int i = 0; i < numVerts; ++i)
		{
			float pos[3];
			in.read((char*)pos, sizeof(float) * 3);
			animVertex[i].position.x = pos[0];	
			animVertex[i].position.y = pos[1];	
			animVertex[i].position.z = pos[2];	

			float normal[3];
			in.read((char*)normal, sizeof(float) * 3);
			animVertex[i].normal.x = normal[0];
			animVertex[i].normal.y = normal[1];
			animVertex[i].normal.z = normal[2];

			float uv[2];
			in.read((char*)uv, sizeof(float) * 2);
			animVertex[i].uv.x = uv[0];
			animVertex[i].uv.y = uv[1];

			int numInfluence;
			in.read((char*)&numInfluence, sizeof(int));

			influences[i].resize(3);

			influences[i][0].jointIndex = 0;
			influences[i][0].weight = 0.0f;
			influences[i][1].jointIndex = 0;
			influences[i][1].weight = 0.0f;
			influences[i][2].jointIndex = 0;
			influences[i][2].weight = 0.0f;

			for(int inf = 0; inf < numInfluence; ++inf)
			{
				if(3 == inf)
					break;

				char buff[128];
				in.read((char*)&size, sizeof(size));
				in.read(buff, size);

				influences[i][inf].name = buff;

				int index;
				float weight;
				in.read((char*)&index, sizeof(int));
				in.read((char*)&weight, sizeof(float));
				influences[i][inf].jointIndex = index;
				influences[i][inf].weight = weight;
			}

			animVertex[i].weights.x = influences[i][0].weight;
			animVertex[i].weights.y = influences[i][1].weight;
			animVertex[i].weights.z = influences[i][2].weight;
			animVertex[i].weightIndices.x = (float)influences[i][0].jointIndex;
			animVertex[i].weightIndices.x = (float)influences[i][1].jointIndex;
			animVertex[i].weightIndices.x = (float)influences[i][2].jointIndex;
		}
		
		m_pDev->CreateVertexBuffer(numVerts * sizeof(TANIMVERTEX), D3DUSAGE_WRITEONLY, 0, D3DPOOL_DEFAULT, &newMesh->pVertBuffer, 0);

		void* buff;
		newMesh->pVertBuffer->Lock(0, 0, &buff, 0);
		memcpy(buff, &animVertex[0], numVerts * sizeof(TANIMVERTEX));
		newMesh->pVertBuffer->Unlock();

		int numTris;
		in.read((char*)&numTris, sizeof(int));

		newMesh->nNumTris = numTris;
		
		unsigned short* indices = new unsigned short[numTris * 3];

		for(int i = 0; i < numTris * 3; i += 3)
		{
			int shor;
			in.read((char*)&shor, sizeof(unsigned int));
			indices[i] = shor;

			in.read((char*)&shor, sizeof(unsigned int));
			indices[i+1] = shor;

			in.read((char*)&shor, sizeof(unsigned int));
			indices[i+2] = shor;
		}

		m_pDev->CreateIndexBuffer(numTris * 3 * sizeof(unsigned short), D3DUSAGE_WRITEONLY, D3DFMT_INDEX16, D3DPOOL_DEFAULT, &newMesh->pIndexBuffer, 0);
		
		newMesh->pIndexBuffer->Lock(0, 0, &buff, 0);
		memcpy(buff, indices, numTris * 3 * sizeof(unsigned short));
		newMesh->pIndexBuffer->Unlock();

		delete[] indices;

		// BONE STRUCTURE
		unsigned int numBones;
		in.read((char*)&numBones, sizeof(unsigned int));
		
		std::vector<TJoint> structure;
		structure.resize(numBones);
		for(unsigned int i = 0; i < numBones; ++i)
		{
			TJoint joint;

			int parent;
			in.read((char*)&parent, sizeof(int));

			if(parent != -1)
				joint.parent = &structure[parent];

			joint.parentIndex = parent;

			in.read((char*)&size, sizeof(size));
			char buff[128];
			in.read(buff, size);

			joint.name = buff;
			
			// loading the world matrix.... into the local variable
			for(unsigned int row = 0; row < 4; ++row)
			{
				for(unsigned int col = 0; col < 4; ++col)
				{
					double val;
					in.read((char*)&val, sizeof(double));
					joint.localMat.m[row][col] = (float)val;
				}
			}

			unsigned int numChildren = 0;
			in.read((char*)&numChildren, sizeof(unsigned int));

			joint.childrenIndex.resize(numChildren);

			for(unsigned int child = 0; child < numChildren; ++child)
			{
				unsigned int temp;
				in.read((char*)&temp, sizeof(unsigned int));
				joint.childrenIndex[child] = &structure[temp];
			}

			structure[i] = joint;
		}

		for(unsigned int i = 0; i < structure.size(); ++i)
		{
			D3DXMATRIX orthonorm = structure[i].GetWorldMat();
			D3DXMatrixInverse(&newMesh->BindPose[i], NULL, &orthonorm);
		}

		m_vMeshes.push_back(newMesh);
	}

	in.close();
	in.clear();

	return 0;
}